/*
1. File System Operators
a) create_vfs (vfs_label,size) – To create a Virtual File System. <vfs_label> is the name
of VFS.
b) mount_vfs (vfs_label) – To Mount the VFS path on current directory. This involves
loading the file/directory descriptors into various data structures
c) unmount_vfs (vfs_label) - To unmount the VFS. It involves saving index information
and tree information back into the hard disk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../include/FileSystemOperations.h"
#include "../include/NAry.h"
#include "../include/BST.h"
#include "../include/HashTable.h"

extern int META_HEADER_START, FILE_DESCRIPTORS_START, FREE_LIST_START, BLOCKS_START;
extern fileSystemInfo fileSysInfo;


int create_vfs(char *label, int size)
{
	if((strcmp(label, "")==0))
		return 0;  

	if(size>1024 || size<=1)
		return 4;

	if(strlen(label)>=30)
		return 5;  

	/*if(!(0<=size)&&(size<=1024))
		return 4;*/

	int i, noOfBlocks;
	FILE *fp;

	for(i=0; label[i]!='\0'; i++)
		if(label[i]=='/' )
			return 3;

	fp = fopen(label, "rb");
	if(fp)
	{
		fclose(fp);	
		return 1; //Data File  Exists
	}

	fp = fopen(label,"wb+");
		if(!fp) 
			return 2;

	fseek(fp,0, SEEK_SET);	
	//Converting size in KBytes to Bytes
	size *= 1024;
	
	//Calculate size of each section...
/*
	If the noOfBlocks = noOfFileDescriptors...
	totalsize = 1*sizeof(MetaHeader) + noOfBlocks*sizeof(fileDescriptor) + noOfBlocks*sizeof(int) + noOfBlocks*sizeof(block) 
	noOfBlocks = ( totalsize - sizeof(MetaHeader) ) / ( sizeof(fileDescriptor) + sizeof(int) + sizeof(block) )

	Otherwise...
	totalsize = 1*sizeof(MetaHeader) + noOfFileDescriptors*sizeof(fileDescriptor) + noOfBlocks*sizeof(int) + noOfBlocks*sizeof(block) 
	noOfBlocks = ( totalsize - sizeof(MetaHeader) - noOfFileDescriptors*sizeof(fileDescriptor) ) / ( sizeof(int) + sizeof(block) )
*/
	//Creating FileSystem Information... Writing it into VFS...

	noOfBlocks = ( size - sizeof(fileSysInfo) ) / ( sizeof(fileDescriptor) + sizeof(int) + sizeof(block) );
		

	strcpy(fileSysInfo.fileSystemLabel, label);
	fileSysInfo.maxFileDescriptors = noOfBlocks;
	fileSysInfo.usedFileDescriptors = 0;
	fileSysInfo.freeBlock = 0;
	fileSysInfo.totalBlocks = noOfBlocks;
	fileSysInfo.isUnmounted = 1;
	fwrite( &fileSysInfo, sizeof(fileSysInfo),1,fp);

	//Creating File Descriptors... Writing File Descriptors...	
	fileDescriptor f;
	for(i=0; i<fileSysInfo.maxFileDescriptors; i++)
		fwrite(&f, sizeof(fileDescriptor), 1, fp);
	//printf("Total size for file descriptors: %ld\n", sizeof(fileDescriptor)*fileSysInfo.maxFileDescriptors);

	//Creating FreeList...
	for(i=0; i<fileSysInfo.totalBlocks; i++)
		fwrite(&i, sizeof(int), 1, fp);

	//Creating Data Blocks... Writing Data Blocks...
	//printf("Number to blocks are: %d\n", fileSysInfo.totalBlocks);
	//printf("Total size data blocks: %ld\n", fileSysInfo.totalBlocks*sizeof(block));
	block b;
	for(i=0; i<fileSysInfo.totalBlocks; i++)
		fwrite(&b, sizeof(block), 1, fp);

	fclose(fp);
	return -1;
 }

int mount_vfs(char *vfs_label)
{
	if((strcmp(vfs_label, "")==0))
		return 0; 

	//strcat(vfs_label,".bin")
	FILE *fp = fopen(vfs_label, "rb");
	if(fp == NULL)
		return 1;
	
	
	//For Data Blocks sizeof(fileSysInfo)+sizeof(fileDescriptor)*fileSysInfo.maxDescriptors
	fseek(fp, 0, SEEK_SET);
	fread(&fileSysInfo, sizeof(fileSysInfo), 1, fp);
	if(isVFSMounted==1)
		return 4;
	isVFSMounted=1;
	fseek(fp, 0, SEEK_SET);
	//Calculating File Limits...
	META_HEADER_START = 0;
	FILE_DESCRIPTORS_START = META_HEADER_START + sizeof(fileSystemInfo);
	FREE_LIST_START = FILE_DESCRIPTORS_START + ( sizeof(fileDescriptor)*(fileSysInfo.maxFileDescriptors) );
	BLOCKS_START = FREE_LIST_START + ( sizeof(int)*fileSysInfo.totalBlocks );
	
/*
	if(fileSysInfo.usedFileDescriptors==0)
		printf("THE VFS IS EMPTY\n");		
					
	printf("Number of Used File Descriptros= %d", fileSysInfo.usedFileDescriptors);
*/
	//Constructing NAry Tree
	int i;
	//Constructing Root of NAry
	BSTRoot = NULL;
	initialize_hash_table();
	NAryNode* nAryNode = insertNAryNode(NULL);
	insert_bst_node(&BSTRoot, "/", nAryNode);
	//Other Nodes of NAry
	fseek(fp, FILE_DESCRIPTORS_START, SEEK_SET);	
	for(i=0; i<fileSysInfo.usedFileDescriptors; i++)
	{
		fileDescriptor fd;
		fread(&fd, sizeof(fileDescriptor), 1, fp);
		if(ferror(fp))
			return 2;
		nAryNode = insertNAryNode(&fd);
		insert_bst_node(&BSTRoot, nAryNode->fd.locationFullPath, nAryNode);
		insert_hash_item(nAryNode->fd.fileName, nAryNode);
	}
	fclose(fp);
	return -1;
}


int unmount_vfs(char *vfs_label)
{
	if(isVFSMounted==0)
		return 3;
	if((strcmp(vfs_label, "")==0))
		return 0; 
	//if(fileSysInfo.isUnmounted==1)
	//	return 3;

	FILE *fp = fopen(vfs_label, "rb");
	if(!fp)
		return 1;
	fclose(fp);
	/*if(strcmp(fileSysInfo.fileSystemLabel, vfs_label) != 0)
		return 2;*/
	fp = fopen(fileSysInfo.fileSystemLabel, "rb+");
	if(!fp)
		return 2;
	persist_nary();
	fseek(fp, META_HEADER_START, SEEK_SET);
	fileSysInfo.isUnmounted = 1;
	fwrite(&fileSysInfo, sizeof(fileSystemInfo), 1, fp);
	fclose(fp);

	isVFSMounted = 0;

	return -1;
}
